﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Browser.Net;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
using System.Reflection;
using System.Diagnostics;

namespace BluePortal.QuikStart.Upload
{
    public partial class PageUpload : Canvas
    {
        private HtmlDocument document;
        private HtmlElement button;
        private BrowserHttpWebRequest _request;

        private string _fileName;
        private Stream _fileToSend;
        private int _fileIndex;
        private int _at;
        private bool _paused;
        private bool _continuing;
        private Stream _rs;
        private List<FileDialogFileInfo> _filesToSend;

        private Canvas canvas1;
        private List<FileDisplay> _fileDisplays;

        private Storyboard _storyboard;
        private DoubleAnimation _flashOnAnim, _flashOffAnim;

        private String _videoId;

        //TextBlock _debugText;

        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();

            try
            {
                document = HtmlPage.Document;
                button = document.GetElementByID("uploadFile");
                bool ec = button.AttachEvent("onclick", new EventHandler(OnUpload));
                document.GetElementByID("pause").AttachEvent("onclick", new EventHandler(Pause));
                document.GetElementByID("resume").AttachEvent("onclick", new EventHandler(Resume)); ;

                _fileDisplays = new List<FileDisplay>();

                //Status to show that loaded ran
                if (ec == true)
                {
                    canvas1 = o as Canvas;

                    _storyboard = (Storyboard)canvas1.FindName("Storyboard");
                    _flashOnAnim = (DoubleAnimation)canvas1.FindName("FlashAnim1");
                    _flashOffAnim = (DoubleAnimation)canvas1.FindName("FlashAnim2");
                    _storyboard.Completed += new EventHandler(Storyboard_Completed);
                    //_debugText = CreateTextBlock(264, 16);
                    //_debugText.Text = "test debug";
                    //_debugText.FontSize = 14;
                    //this.canvas1.Children.Add(_debugText);

                }
            }
            catch (Exception ex)
            {
                string message = ex.Message;
            }
        }

        #region generic calls to WebService
        void CallWS(Uri wsUri, AsyncCallback asyncMethod, string requestString)
        {
            byte[] dat;
            Stream rs = null;

            UTF8Encoding encoding = new UTF8Encoding();
            dat = encoding.GetBytes(requestString);
            //Now build the network request
            try
            {

                //_debugText.Text = WebApplication.Current.StartupArguments["uploadUrl"]; 

                BrowserHttpWebRequest request = new BrowserHttpWebRequest(wsUri);


                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = dat.Length;
                rs = request.GetRequestStream();
                rs.Write(dat, 0, dat.Length);

                //And then submit the request
                IAsyncResult iar = request.BeginGetResponse(asyncMethod, request);
            }
            catch (Exception ex)
            {
                document.GetElementByID("aa").SetAttribute("innerHtml", ex.Message);
            }
            finally
            {
                if (rs != null)
                    rs.Close();
            }
        }

        #endregion

        #region async upload section
        private void OnUpload(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.EnableMultipleSelection = false;
            ofd.Filter = "All files|*.*";
            ofd.Title = "Select a file to upload";

            if (ofd.ShowDialog() == DialogResult.OK)
            {

                //Hide Button
                document.GetElementByID("uploadFile").SetStyleAttribute("display", "none");


                canvas1.Children.Clear();
                _fileDisplays.Clear();

                _continuing = false;
                _paused = false;

                int fileNumber = 0;

                foreach (FileDialogFileInfo fdfi in ofd.SelectedFiles)
                {
                    fileNumber++;
                }
                Rectangle r = CreateRectangle(432, 16 + fileNumber * 56, 15.5);
                r.Stroke = new SolidColorBrush(Colors.Black);
                r.Fill = new SolidColorBrush(Color.FromRgb(0x13, 0x13, 0x13));
                canvas1.Children.Add(r);

                _filesToSend = new List<FileDialogFileInfo>();
                fileNumber = 0;
                foreach (FileDialogFileInfo fdfi in ofd.SelectedFiles)
                {
                    _filesToSend.Add(fdfi);
                    FileDisplay fd = CreateFileDisplay(fdfi.Name, fileNumber);
                    _fileDisplays.Add(fd);
                    fd.Canvas.RenderTransform = CreateTranslate(16, 16 + 56 * fileNumber);
                    canvas1.Children.Add(fd.Canvas);
                    fileNumber++;
                }
                _fileIndex = -1;
                SendNextFile();
            }
        }

        private void SendNextFile()
        {
            if (_continuing)
            {
                _continuing = false;
                HtmlPage.Cookies = ExpireCookie();
            }

            _at = 0;
            _fileIndex++;
            if (_fileIndex < _filesToSend.Count)
            {

                if (_fileToSend != null)
                    _fileToSend.Close();

                _fileToSend = _filesToSend[_fileIndex].OpenRead();
                _fileName = _filesToSend[_fileIndex].Name;
            }

            if (!String.IsNullOrEmpty(HtmlPage.Cookies))
            {
                string[] allCookies = HtmlPage.Cookies.Split(';');
                foreach (string c in allCookies)
                {
                    if (c.Trim().StartsWith("uploadState="))
                    {
                        string cookie = c.Trim();
                        if (cookie.IndexOf('|') > -1)
                        {
                            cookie = cookie.Substring("uploadState=".Length);
                            int at = Convert.ToInt32(cookie.Substring(0, cookie.IndexOf('|')));
                            cookie = cookie.Substring(cookie.IndexOf('|') + 1);

                            if (cookie.IndexOf('|') > -1)
                            {
                                int total = Convert.ToInt32(cookie.Substring(0, cookie.IndexOf('|')));
                                string fileName = cookie.Substring(cookie.IndexOf('|') + 1);

                                if (fileName.Equals(_fileName, StringComparison.Ordinal) && _fileToSend.Length == total)
                                {
                                    _at = at;
                                    _fileToSend.Seek(_at, SeekOrigin.Begin);
                                    _continuing = true;
                                    //TODO: may be break ??
                                }
                            }
                        }
                    }
                }
            }

            if (_at < _fileToSend.Length && _fileIndex < _filesToSend.Count)
            {
                SendNextChunk();
            }
            else
            {
            }
        }

        private void SendNextChunk()
        {
            //Close the previous request if one exists.
            if (_request != null)
                _request.Close();

            if (!_paused)
            {
                int maxLen = 1024 * 500;
                int length = (int)(_fileToSend.Length - _at);
                if (length > maxLen)
                {
                    length = maxLen;
                }

                byte[] dat = new byte[length];
                _fileToSend.Read(dat, 0, length);

                StringBuilder requestString = new StringBuilder();
                requestString.Append("fileName=");
                _videoId = WebApplication.Current.StartupArguments["videoId"];
                requestString.Append(HttpUtility.UrlEncode(_videoId));
                requestString.Append("&isNew=");
                requestString.Append(_at == 0);
                requestString.Append("&base64Encoded=");
                requestString.Append(HttpUtility.UrlEncode(Convert.ToBase64String(dat)));

                //Convert the request string to a request body

                UTF8Encoding encoding = new UTF8Encoding();
                dat = encoding.GetBytes(requestString.ToString());

                //Now build the network request
                try
                {

                    //_debugText.Text = WebApplication.Current.StartupArguments["uploadUrl"]; 

                    _request = new BrowserHttpWebRequest(new Uri("http://" +
                        HtmlPage.DocumentUri.DnsSafeHost + WebApplication.Current.StartupArguments["uploadUrl"] + "/SendChunk"));


                    _request.Method = "POST";
                    _request.ContentType = "application/x-www-form-urlencoded";
                    _request.ContentLength = dat.Length;
                    _rs = _request.GetRequestStream();
                    _rs.Write(dat, 0, dat.Length);

                    //And then submit the request
                    IAsyncResult iar = _request.BeginGetResponse(new AsyncCallback(ChunkSent), null);
                }
                catch (Exception ex)
                {
                    document.GetElementByID("aa").SetAttribute("innerHtml", ex.Message);
                }
                finally
                {
                    _rs.Close();  //CHANGED
                }

                _at += length;
            }
        }

        public void ChunkSent(IAsyncResult iar)
        {
            try
            {
                HttpWebResponse response = _request.EndGetResponse(iar);
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    _fileDisplays[_fileIndex].ProgressText.Text = (_at / 1024) + "/" + (_fileToSend.Length / 1024) + "K";
                    _fileDisplays[_fileIndex].ProgressBar.Width = 384 * ((double)_at / _fileToSend.Length);

                    if (_at == _fileToSend.Length)
                    {
                        string flashName = _fileDisplays[_fileIndex].ProgressFlash.Name;
                        _flashOnAnim.SetValue<string>(Storyboard.TargetNameProperty, String.Empty);
                        _flashOnAnim.SetValue<string>(Storyboard.TargetNameProperty, flashName);
                        _flashOffAnim.SetValue<string>(Storyboard.TargetNameProperty, flashName);
                        _storyboard.Begin();
                    }
                    else
                    {
                        if (_at < _fileToSend.Length && _fileIndex < _filesToSend.Count)
                        {
                            SendNextChunk();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                document.GetElementByID("aa").SetAttribute("innerHtml", ex.Message);
            }
            finally
            {
            }
        }
        #endregion
        #region async uploaded section
        public void UploadedCompletedCallBack(IAsyncResult iar)
        {
            BrowserHttpWebRequest ws = (BrowserHttpWebRequest)iar.AsyncState;
            HttpWebResponse response = ws.EndGetResponse(iar);
        }

        private void Storyboard_Completed(object sender, EventArgs e)
        {
            _storyboard.Stop();

            StringBuilder requestString = new StringBuilder();
            requestString.Append("videoID=");
            _videoId = WebApplication.Current.StartupArguments["videoId"];
            requestString.Append(HttpUtility.UrlEncode(_videoId));
            try
            {
                string wsUrl = WebApplication.Current.StartupArguments["uploadedUrl"];
                Uri wsuri = new Uri("http://" + HtmlPage.DocumentUri.DnsSafeHost + wsUrl + "/FileUploaded");
                CallWS(wsuri, UploadedCompletedCallBack, requestString.ToString());

            }
            catch (Exception ex)
            {
                document.GetElementByID("aa").SetAttribute("innerHtml", ex.Message);
            }

            canvas1.Children.Clear();

            Rectangle background = CreateRectangle(400, 40, 7.5);
            background.Stroke = new SolidColorBrush(Colors.Black);
            background.Fill = new SolidColorBrush(Color.FromRgb(0xce, 0xce, 0xce));

            canvas1.Children.Add(background);

            TextBlock UpComplet = CreateTextBlock(264, 40);
            UpComplet.Text = "Upload Complete";
            UpComplet.RenderTransform = CreateTranslate(16, 4);
            UpComplet.FontSize = 24;
            canvas1.Children.Add(UpComplet);
            document.GetElementByID("pause").SetStyleAttribute("display", "none");
            document.GetElementByID("resume").SetStyleAttribute("display", "none");

            SendNextFile();
        }
        #endregion

        public void Pause(object sender, EventArgs e)
        {
            if (_filesToSend != null && !_paused)
            {
                HtmlPage.Cookies = GetCookie();
                _paused = true;
            }
        }

        public void Resume(object sender, EventArgs e)
        {
            if (_filesToSend != null && _paused)
            {
                _paused = false;
                SendNextChunk();
            }
        }

        private string GetCookie()
        {
            DateTime expire = DateTime.Now.Add(new TimeSpan(24, 0, 0)).ToUniversalTime();
            string expireString = expire.ToString("ddd, dd-MMM-yyyy HH:mm:ss") + " GMT";
            return "uploadState=" + _at + "|" + _fileToSend.Length + "|" + _fileName + "; expires=" + expireString + ";";
        }

        private string ExpireCookie()
        {
            DateTime expire = DateTime.Now.Add(new TimeSpan(-24, 0, 0)).ToUniversalTime();
            string expireString = expire.ToString("ddd, dd-MMM-yyyy HH:mm:ss") + " GMT";
            return "uploadState=a; expires=" + expireString + ";";
        }

        private Rectangle CreateRectangle(double width, double height, double radius)
        {
            Rectangle r = new Rectangle();
            r.Width = width;
            r.Height = height;
            r.RadiusX = radius;
            r.RadiusY = radius;
            return r;
        }

        private TextBlock CreateTextBlock(double width, double height)
        {
            TextBlock tb = new TextBlock();
            tb.Width = width;
            tb.Height = height;
            tb.FontSize = 10;
            return tb;
        }

        private TranslateTransform CreateTranslate(double x, double y)
        {
            TranslateTransform translate = new TranslateTransform();
            translate.X = x;
            translate.Y = y;
            return translate;
        }

        private ScaleTransform CreateScale(double x, double y, double scale)
        {
            ScaleTransform st = new ScaleTransform();
            st.CenterX = x;
            st.CenterY = y;
            st.ScaleX = scale;
            st.ScaleY = scale;
            return st;
        }

        private Canvas CreateCanvas(double width, double height, double radius)
        {
            Canvas c = new Canvas();
            c.Width = width;
            c.Height = height;
            c.Clip = CreateRectangleGeometry(width, height, radius);
            return c;
        }

        private RectangleGeometry CreateRectangleGeometry(double width, double height, double radius)
        {
            RectangleGeometry rg = new RectangleGeometry();
            rg.Rect = new Rect(0, 0, width, height);
            rg.RadiusX = radius;
            rg.RadiusY = radius;
            return rg;
        }

        private DoubleAnimation CreateDoubleAnimation(double from, double to, int seconds, int milliseconds, string name, string property)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.From = from;
            da.To = to;
            da.Duration = new Duration(new TimeSpan(0, 0, seconds, milliseconds));
            da.SetValue<string>(Storyboard.TargetNameProperty, name);
            da.SetValue<string>(Storyboard.TargetPropertyProperty, property);
            return da;
        }

        private FileDisplay CreateFileDisplay(string fileName, int fileNumber)
        {
            FileDisplay disp = new FileDisplay();

            Canvas c = CreateCanvas(400, 40, 7.5);
            disp.Canvas = c;

            Rectangle background = CreateRectangle(400, 40, 7.5);
            background.Stroke = new SolidColorBrush(Colors.Black);
            background.Fill = new SolidColorBrush(Color.FromRgb(0xce, 0xce, 0xce));

            c.Children.Add(background);

            Canvas progress = CreateCanvas(384, 12, 5.5);
            progress.RenderTransform = CreateTranslate(8, 20);
            progress.Background = new SolidColorBrush(Colors.White);
            c.Children.Add(progress);

            Rectangle progressBar = CreateRectangle(0, 12, 0);
            disp.ProgressBar = progressBar;
            progressBar.Fill = new SolidColorBrush(Colors.Green);
            progress.Children.Add(progressBar);

            Rectangle emptyProgressBar = CreateRectangle(384, 12, 5.5);
            emptyProgressBar.Stroke = new SolidColorBrush(Colors.Black);
            progress.Children.Add(emptyProgressBar);

            Rectangle progressFlash = CreateRectangle(400, 40, 7.5);
            disp.ProgressFlash = progressFlash;
            progressFlash.SetValue<string>(DependencyObject.NameProperty, "Flash" + fileNumber);
            progressFlash.Opacity = 0.0;
            progressFlash.Fill = new SolidColorBrush(Colors.White);
            c.Children.Add(progressFlash);

            TextBlock fileNameText = CreateTextBlock(264, 16);
            disp.FileName = fileNameText;
            fileNameText.Text = fileName;
            fileNameText.RenderTransform = CreateTranslate(16, 4);
            fileNameText.FontSize = 14;
            c.Children.Add(fileNameText);

            TextBlock progressText = CreateTextBlock(88, 16);
            disp.ProgressText = progressText;
            progressText.RenderTransform = CreateTranslate(296, 4);
            progressText.FontSize = 14;
            c.Children.Add(progressText);

            return disp;
        }
    }

    internal class FileDisplay
    {
        public Canvas Canvas;
        public Rectangle ProgressBar;
        public TextBlock FileName;
        public TextBlock ProgressText;
        public Rectangle ProgressFlash;
    }

}
